<template>
  <!-- Add a single root div -->
  <div class="file-manager-view-wrapper">
    <div class="file-manager-view" @click.self="handleClickOutside">
      <el-card
          ref="cardRef"
          shadow="never"
          @click.self="handleClickOutside"
      >
        <template #header>
          <div class="card-header">
            <!-- Restore Breadcrumbs -->
            <el-breadcrumb class="breadcrumb-nav" separator="/">
              <!-- Iterate over breadcrumbs and wrap each item -->
              <template v-for="(crumb, index) in breadcrumbs" :key="crumb.uuid || 'root'">
                <div
                    class="breadcrumb-wrapper breadcrumb-hover-target"
                    :data-crumb-uuid="crumb.uuid || 'root'"
                    :class="{
                    'breadcrumb-drop-target-hover': hoveredCrumbUuid === crumb.uuid && crumb.uuid !== null && index < breadcrumbs.length - 1
                  }"
                >
                  <el-breadcrumb-item
                      :to="index < breadcrumbs.length - 1 ? { path: '#', query: { folderId: crumb.uuid } } : undefined"
                      @click.prevent="index < breadcrumbs.length - 1 ? navigateTo(crumb.uuid) : null"
                  >
                    {{ crumb.name }}
                  </el-breadcrumb-item>
                </div>
              </template>
            </el-breadcrumb>

            <div class="actions">
              <!-- Buttons call updated actions, use isLoading computed from fileManagerStore -->
              <el-button :icon="FolderAdd" :loading="isLoading" type="warning" @click="handleCreateFolderClick">
                新建文件夹
              </el-button>
              <el-button :icon="DocumentAdd" :loading="isLoading" type="success" @click="showCreateFileDialog">新建文件
              </el-button>
              <el-button :icon="Upload" :loading="isLoading" type="primary" @click="triggerFileUpload">上传文件
              </el-button>
              <input ref="fileInput" accept=".jdf,.xml" style="display: none" type="file" @change="handleFileUpload"/>
            </div>
          </div>
        </template>

        <!-- Simulated Header Row -->
        <div class="list-header">
          <!-- Skip Icon Column -->
          <span
              class="header-item header-name"
              :class="{ 'is-active': currentSortKey === 'name', 'is-asc': currentSortDirection === 'asc', 'is-desc': currentSortDirection === 'desc' }"
              @click="handleSort('name')"
          >名称</span>
          <span
              class="header-item header-type"
              :class="{ 'is-active': currentSortKey === 'type', 'is-asc': currentSortDirection === 'asc', 'is-desc': currentSortDirection === 'desc' }"
              @click="handleSort('type')"
          >类型</span>
          <span
              class="header-item header-size"
              :class="{ 'is-active': currentSortKey === 'size', 'is-asc': currentSortDirection === 'asc', 'is-desc': currentSortDirection === 'desc' }"
              @click="handleSort('size')"
          >大小</span>
          <span
              class="header-item header-date"
              :class="{ 'is-active': currentSortKey === 'lastModified', 'is-asc': currentSortDirection === 'asc', 'is-desc': currentSortDirection === 'desc' }"
              @click="handleSort('lastModified')"
          >修改日期</span>
        </div>

        <div
            v-if="currentItems.length > 0"
            class="simple-list-container"
            @click.self="handleClickOutside"
        >
          <ul style="list-style: none; padding: 0; margin: 0;">
            <li
                v-for="item in currentItems"
                :key="item.uuid"
                :class="{
                    'is-focused': selectedItemId === item.uuid,
                    'is-renaming': editingItemId === item.uuid,
                    'is-focus-ghost': focusGhostItemId === item.uuid,
                    'is-renaming-input-hover': editingItemId === item.uuid && isHoveringInputWhileRenaming,
                    'is-context-menu-active': contextMenu.show && contextMenu.targetItem?.uuid === item.uuid
                }"
                class="filesystem-item-li"
            >
              <!-- Restore Draggable/Droppable wrappers -->
              <DropTargetFolder v-if="item.type === 'folder'" :item="item">
                <DraggableItem :item="item">
                  <div
                      class="item-content"
                      @click="handleItemClick(item, $event)"
                      @dblclick="handleItemDoubleClick(item, $event)"
                      @contextmenu.prevent="onRowContextMenu(item, null, $event)"
                  >
                    <el-icon :size="16" class="item-icon">
                      <!-- Conditional icon based on item type -->
                      <component :is="item.type === 'folder' ? FolderIcon : DocumentIcon" />
                    </el-icon>
                    <el-input
                        v-if="editingItemId === item.uuid"
                        :ref="(el: unknown) => { if (el) nameInputRef[0] = el }"
                        v-model="editingNameModel"
                        class="name-input"
                        @mouseenter="handleInputMouseEnter"
                        @mouseleave="handleInputMouseLeave"
                        @keydown.enter.prevent="confirmRename"
                        @keydown.esc.prevent="cancelRename"
                        @blur="confirmRename"
                    />
                    <!-- Wrap static info in template v-else -->
                    <template v-else>
                      <span class="item-name">{{ item.name }}</span>
                      <span class="item-type">{{ formatType(item) }}</span>
                      <span class="item-size">{{ formatSize(item.size) }}</span>
                      <span class="item-modified">{{ formatDate(item.lastModified) }}</span>
                    </template>
                  </div>
                </DraggableItem>
              </DropTargetFolder>

              <!-- Restore direct rendering for non-folder items -->
              <DraggableItem v-else :item="item">
                <div
                    class="item-content"
                    @click="handleItemClick(item, $event)"
                    @dblclick="handleItemDoubleClick(item, $event)"
                    @contextmenu.prevent="onRowContextMenu(item, null, $event)"
                >
                  <el-icon :size="16" class="item-icon">
                    <DocumentIcon/>
                  </el-icon>
                  <el-input
                      v-if="editingItemId === item.uuid"
                      :ref="(el: unknown) => { if (el) nameInputRef[0] = el }"
                      v-model="editingNameModel"
                      class="name-input"
                      @mouseenter="handleInputMouseEnter"
                      @mouseleave="handleInputMouseLeave"
                      @keydown.enter.prevent="confirmRename"
                      @keydown.esc.prevent="cancelRename"
                      @blur="confirmRename"
                  />
                  <!-- Wrap static info in template v-else -->
                  <template v-else>
                    <span class="item-name">{{ item.name }}</span>
                    <span class="item-type">{{ formatType(item) }}</span>
                    <span class="item-size">{{ formatSize(item.size) }}</span>
                    <span class="item-modified">{{ formatDate(item.lastModified) }}</span>
                  </template>
                </div>
              </DraggableItem>
            </li>
          </ul>
        </div>

        <!-- Empty state: Use isLoading from fileManagerStore -->
        <el-empty v-if="!isLoading && currentItems.length === 0" description="您还没有上传或创建任何文件或文件夹。"/>

      </el-card>
      <!-- Context Menu -->
      <ContextMenu
          v-model:show="contextMenu.show"
          :options="contextMenuOptions"
      >
        <template #itemRender="{ icon, label, disabled, showRightArrow, onClick, onMouseEnter }">
          <div
              :class="['custom-context-menu-item', { 'disabled': disabled }]"
              @click="onClick"
              @mouseenter="onMouseEnter"
          >
            <component
                :is="icon"
                v-if="icon"
                class="menu-item-icon"
            />
            <div v-else class="menu-item-icon-placeholder"></div>
            <span class="menu-item-label">{{ label }}</span>
            <span v-if="showRightArrow" class="submenu-arrow">&gt;</span>
          </div>
        </template>
      </ContextMenu>
      <!-- Dialogs (No change needed in template, logic updated in script) -->
      <el-dialog
          v-model="dialogVisible"
          :title="dialogMode === 'createFolder' ? '新建文件夹' : (dialogMode === 'createFile' ? '新建文件' : '重命名')"
          width="400px"
          @closed="resetDialog"
      >
        <!-- Add the form content here -->
        <el-form
            ref="dialogFormRef"
            :model="dialogForm"
            :rules="dialogRules"
            label-position="top"
            @submit.prevent="submitDialog"
        >
          <el-form-item label="名称" prop="name">
            <el-input v-model="dialogForm.name" autocomplete="off" placeholder="请输入名称"/>
          </el-form-item>
        </el-form>
        <!-- End form content -->
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="dialogVisible = false">取消</el-button>
            <el-button :loading="isDialogLoading" type="primary" @click="submitDialog">
              确认
            </el-button>
          </span>
        </template>
      </el-dialog>

      <el-dialog
          v-model="moveDialogVisible"
          :close-on-click-modal="false"
          :title="moveDialogTitle"
          width="450px"
      >
        <!-- ... move dialog form ... -->
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="moveDialogVisible = false">取消</el-button>
            <el-button
                :disabled="selectedTargetFolderId === undefined"
                :loading="isMoveDialogLoading"
                type="primary"
                @click="submitMoveDialog"
            >
              移动
            </el-button>
          </span>
        </template>
      </el-dialog>

    </div>

    <!-- Global Rename Spotlight Overlay -->
    <Transition name="spotlight">
      <div v-if="isRenamingActive" ref="overlayRef" class="global-rename-spotlight-overlay"></div>
    </Transition>

    <!-- Hidden SVG definitions for masks -->
    <svg height="0" style="position: absolute;" width="0">
      <defs>
        <mask id="rename-spotlight-mask" maskContentUnits="objectBoundingBox" maskUnits="objectBoundingBox">
          <rect fill="white" height="1" width="1"/>
          <!-- The black circle creates the transparent spotlight area -->
          <!-- cx, cy = 0.5 means center. r=0.15 means radius is 15% of the element size -->
          <circle cx="0.5" cy="0.5" fill="black" r="0.15"/>
        </mask>
      </defs>
    </svg>

    <!-- Hidden Canvas for text measurement -->
    <canvas ref="textMeasureCanvasRef" class="text-measure-canvas"></canvas>
  </div>
</template>


<script lang="ts" setup>
import {ref, computed, onMounted, reactive, nextTick, watch, type Ref, watchEffect, onUnmounted, onBeforeUnmount, onUpdated} from 'vue';
import {useRouter} from 'vue-router';
// Import the new file manager store
import {useFileManagerStore} from '@/stores/fileManagerStore.ts';
// Import settings store to check the new setting
import {useSettingsStore} from '@/stores/settingsStore.ts';
// Remove the old editor store import if no longer needed for editor-specific state
// import { useJDFStore } from '@/stores/editorStore.ts'; // Now named useEditorStore
import {ElMessage, ElMessageBox} from 'element-plus';
import {
  Upload,
  DocumentAdd,
  FolderAdd,
  FolderOpened,
  Delete,
  Document as DocumentIcon,
  Folder as FolderIcon,
  Rank,
  Download
} from '@element-plus/icons-vue';
// Keep IndexedDB types if needed for local type hints, though store should abstract this
import type {StoredJDFFileMeta, StoredJDFFile} from '@/utils/indexedDBService';
import type {FilesystemItemMeta, StoredJDFFolderMeta} from '@/utils/indexedDBService';
import type {FormInstance, FormRules} from 'element-plus';
// DnD Components
import DraggableItem from '@/components/dnd/DraggableItem.vue';
import DropTargetFolder from '@/components/dnd/DropTargetFolder.vue';
// Import VueUse function
import {onClickOutside} from '@vueuse/core';
// Import the new composable
import {useFileItemInteraction} from '@/composables/useFileItemInteraction';
// Import VueUse composable
import { useDropZone, useEventListener } from '@vueuse/core';
// Import SortKey type from store
import type { SortKey } from '@/stores/fileManagerStore.ts';
import { useDebounceFn } from '@vueuse/core'; // Ensure debounce is imported if needed

console.log('[FileManagerView] Script setup execution start.');

const router = useRouter();
// Use the new file manager store
const fileManagerStore = useFileManagerStore();
// Use settings store
const settingsStore = useSettingsStore(); // Get settings store instance
const fileInput = ref<HTMLInputElement | null>(null);

// Ref for the main card element to be used as drop zone
const cardRef = ref<HTMLElement | null>(null);

// --- Editing State refs (managed by composable now, but need model ref) ---
const nameInputRef = ref<any[]>([]); // Keep ref for input elements (type any for ElInput instance)
const editingNameModel = ref<string>(''); // Model for the input field

// --- Use the composable --- RESTORE / CORRECTED
console.log('[DEBUG FileManagerView] Initializing useFileItemInteraction...');
const {
  selectedItemId,
  editingItemId,
  focusGhostItemId,
  handleItemClick,
  handleItemDoubleClick,
  handleClickOutside,
  startRename: composableStartRename, // Rename imported function to avoid conflict if local wrapper exists
  confirmRename: composableConfirmRename,
  cancelRename: composableCancelRename,
  isHoveringInputWhileRenaming,
  handleInputMouseEnter,
  handleInputMouseLeave,
  contextMenuPendingTargetId,
  contextMenuTimeoutId,
  cancelContextMenu
} = useFileItemInteraction(nameInputRef, editingNameModel);

console.log('[DEBUG FileManagerView] useFileItemInteraction initialized.');

// --- Local Wrappers for Rename (Optional, for adding logs easily) ---
// These wrappers allow adding logs before/after calling the original composable functions
const startRename = (item: FilesystemItemMeta) => {
  console.log(`[DEBUG FileManagerView startRename] Wrapper called for item: ${item.uuid} (${item.name})`);
  composableStartRename(item);
  console.log(`[DEBUG FileManagerView startRename] After calling composableStartRename. Current editingItemId: ${editingItemId.value}`);
}

const confirmRename = () => {
  console.log(`[DEBUG FileManagerView confirmRename] Wrapper called. Current editingItemId: ${editingItemId.value}, Model: ${editingNameModel.value}`);
  composableConfirmRename();
  console.log(`[DEBUG FileManagerView confirmRename] After calling composableConfirmRename. Current editingItemId: ${editingItemId.value}`);
}

const cancelRename = () => {
  console.log(`[DEBUG FileManagerView cancelRename] Wrapper called. Current editingItemId: ${editingItemId.value}`);
  composableCancelRename();
  console.log(`[DEBUG FileManagerView cancelRename] After calling composableCancelRename. Current editingItemId: ${editingItemId.value}`);
}

// Ref for the global overlay element
const overlayRef = ref<HTMLDivElement | null>(null);

// Ref for the hidden canvas used for text measurement
const textMeasureCanvasRef = ref<HTMLCanvasElement | null>(null);

// Computed property to check if renaming is active
const isRenamingActive = computed(() => {
  // console.log('[FileManagerView computed] isRenamingActive evaluated:', !!editingItemId.value);
  return !!editingItemId.value;
});

// --- State for newly created folder (still needed locally) ---
const newlyCreatedFolderId = ref<string | null>(null);

// --- Dialog State (Keep as is for file creation/rename file/rename folder initially) ---
const dialogVisible = ref(false);
const isDialogLoading = ref(false);
const dialogMode = ref<'createFolder' | 'createFile' | 'renameFolder' | 'renameFile'>('createFolder');
const renameTarget = ref<FilesystemItemMeta | null>(null);
const dialogFormRef = ref<FormInstance>();
const dialogForm = reactive({name: ''});
const dialogRules = reactive<FormRules>({
  name: [
    {required: true, message: '名称不能为空', trigger: 'blur'},
    {pattern: /^[^\/]+$/, message: '名称不能包含斜杠', trigger: 'blur'},
  ],
});

// --- Move Dialog State (Keep as is) ---
const moveDialogVisible = ref(false);
const isMoveDialogLoading = ref(false);
const itemToMove = ref<FilesystemItemMeta | null>(null);
const allFolders = ref<StoredJDFFolderMeta[]>([]);
const selectedTargetFolderId = ref<string | null>(null);

// --- Breadcrumb Drag-to-Open State ---
const hoveredCrumbUuid = ref<string | null>(null);
const openFolderTimerId = ref<ReturnType<typeof setTimeout> | null>(null);
const BREADCRUMB_HOVER_DELAY = 1500; // ms to wait before opening
// -------------------------------------

// --- Computed Properties ---
const currentItems = computed(() => fileManagerStore.currentItems);
const breadcrumbs = computed(() => fileManagerStore.breadcrumbs);
const isLoading = computed(() => fileManagerStore.isDBLoading);
// Computed property for the current folder ID (used to disable last breadcrumb hover)
const currentFolderId = computed(() => fileManagerStore.currentFolderId);
// Expose sort state for potential UI indicators
const currentSortKey = computed(() => fileManagerStore.sortKey);
const currentSortDirection = computed(() => fileManagerStore.sortDirection);

// --- Context Menu State & Logic (Moved Before Watchers) ---
const contextMenu = reactive({
  show: false,
  targetItem: null as FilesystemItemMeta | null,
  x: 0,
  y: 0
});

const contextMenuOptions = computed(() => {
  const item = contextMenu.targetItem;
  console.log(`[FileManagerView computed] contextMenuOptions evaluated. Target item: ${item?.uuid}`);
  const options: any[] = [];
  if (!item) return {items: [], x: 0, y: 0};

  if (item.type === 'file') {
    // Use loadFile action
    options.push({label: '打开文件', icon: DocumentIcon, onClick: () => loadFile(item.uuid)});
    // Use downloadFile action
    options.push({label: '下载文件', icon: Download, onClick: () => downloadFile(item.uuid, item.name)});
  } else {
    // Use navigateTo action
    options.push({label: '打开文件夹', icon: FolderOpened, onClick: () => navigateTo(item.uuid)});
  }
// Use startRename from composable
  options.push({label: '重命名', onClick: () => startRename(item)});
  // Use showMoveDialog (local, calls store action)
  options.push({label: '移动到...', icon: Rank, onClick: () => showMoveDialog(item)});
  options.push({type: 'divider'});
  options.push({
    label: '删除',
    icon: Delete,
    onClick: () => {
      if (item.type === 'file') {
        // Use deleteFile action
        deleteFile(item.uuid, item.name);
      } else {
        // Use deleteFolder action
        deleteFolder(item.uuid, item.name);
      }
    }
  });

  // Theme/Style remains the same
  return {
    items: options,
    x: contextMenu.x,
    y: contextMenu.y,
    theme: useSettingsStore().darkMode ? 'dark' : 'light',
    zIndex: 3000,
    minWidth: 150
  };
});

const onRowContextMenu = (row: FilesystemItemMeta, column: any, event: MouseEvent) => {
  console.log(`[FileManagerView onRowContextMenu] Context menu event for: ${row.uuid}`);
  event.preventDefault();

  // 1. Immediately select the item
  console.log('[FileManagerView onRowContextMenu] Calling handleItemClick for selection.');
  handleItemClick(row, event); // Use existing click handler for selection logic
  // If renaming, cancel it
  if (editingItemId.value === row.uuid) {
    console.log('[FileManagerView onRowContextMenu] Was renaming, cancelling rename.');
    cancelRename();
  }

  // 2. Cancel any existing pending menu timer
  console.log('[FileManagerView onRowContextMenu] Cancelling pending context menu timer.');
  cancelContextMenu();

  // 3. Set pending state and store necessary info
  contextMenuPendingTargetId.value = row.uuid; // Mark this item as pending
  contextMenu.targetItem = row; // Store target for menu options
  // Store coordinates with a small offset to reduce overlap issues
  const offsetX = -20; // pixels
  const offsetY = -20; // pixels
  contextMenu.x = event.clientX + offsetX;
  contextMenu.y = event.clientY + offsetY;
  contextMenu.show = false; // Ensure menu is not shown yet
  console.log(`[FileManagerView onRowContextMenu] Set pending target: ${row.uuid}. Coords: (${contextMenu.x}, ${contextMenu.y}). Starting timer...`);

  // 4. Start the 0.2s timer
  contextMenuTimeoutId.value = setTimeout(() => {
    // Check if the pending target is still the same (no other clicks cancelled it)
    if (contextMenuPendingTargetId.value === row.uuid) {
      console.log(`[FileManagerView onRowContextMenu] Context menu timer fired for: ${row.uuid}. Showing menu.`);
      contextMenu.show = true; // Show the menu
      contextMenuPendingTargetId.value = null; // Clear pending state
      contextMenuTimeoutId.value = null; // Clear timeout ID
    } else {
      console.log(`[FileManagerView onRowContextMenu] Context menu timer fired but target changed or cancelled for: ${row.uuid}.`);
    }
  }, 200); // 200ms delay
};

// --- Breadcrumb Drag Handlers (using native DOM API) ---
const clearOpenFolderTimer = () => {
  if (openFolderTimerId.value) {
    console.log(`[FileManagerView clearOpenFolderTimer] Clearing timer ID: ${openFolderTimerId.value}`);
    clearTimeout(openFolderTimerId.value);
    openFolderTimerId.value = null;
  }
  if (hoveredCrumbUuid.value) {
    console.log(`[FileManagerView clearOpenFolderTimer] Resetting hoveredCrumbUuid: ${hoveredCrumbUuid.value}`);
    hoveredCrumbUuid.value = null; // Reset hover state when timer is cleared
  }
};

// --- Initialize useDropZone ---
const { isOverDropZone } = useDropZone(cardRef, {
  // Specify the data types we expect from DraggableItem
  dataTypes: ['application/json', 'text/plain']
});

// --- New Handler Functions for dragover (MOVED HERE) ---
const handleZoneDragOver = (event: DragEvent) => {
  // Prevent default to allow dropping and other events
  event.preventDefault();
  // Set drop effect for visual feedback
  if (event.dataTransfer) {
    event.dataTransfer.dropEffect = 'move';
  }

  // Only proceed if the drag is actually over our target card zone
  if (!isOverDropZone.value) {
    // If not over the zone, ensure any existing timer is cleared
    if (hoveredCrumbUuid.value !== null) {
      // console.log('[FileManagerView handleZoneDragOver] Not over drop zone, clearing timer.');
      clearOpenFolderTimer();
    }
    return;
  }

  // console.log('[FileManagerView handleZoneDragOver] Fired via useEventListener while isOverDropZone is true.');

  // Logic to find the breadcrumb target under the cursor
  const elementsUnderCursor = document.elementsFromPoint(event.clientX, event.clientY);
  let targetCrumbWrapper: HTMLElement | null = null;
  for (const element of elementsUnderCursor) {
    if (element.classList.contains('breadcrumb-hover-target')) {
      targetCrumbWrapper = element as HTMLElement;
      break;
    }
  }

  let targetCrumbUuid: string | null = null;
  if (targetCrumbWrapper) {
    const uuidAttr = targetCrumbWrapper.dataset.crumbUuid;
    targetCrumbUuid = uuidAttr === 'root' ? null : uuidAttr || null;
  }

  // Timer logic based on the found target
  if (targetCrumbUuid !== null && targetCrumbUuid !== currentFolderId.value) {
    // Hovering over a valid, non-current breadcrumb
    if (hoveredCrumbUuid.value !== targetCrumbUuid) {
      // Entered a new valid crumb target
      console.log(`[FileManagerView handleZoneDragOver] Entered new valid crumb: ${targetCrumbUuid}. Starting timer.`);
      clearOpenFolderTimer();
      hoveredCrumbUuid.value = targetCrumbUuid;

      openFolderTimerId.value = setTimeout(() => {
        console.log(`[FileManagerView Timer CB] Timer fired for crumb: ${targetCrumbUuid}. Current hovered: ${hoveredCrumbUuid.value}`);
        if (hoveredCrumbUuid.value === targetCrumbUuid) {
          console.log(`[FileManagerView Timer CB] Navigating to folder: ${targetCrumbUuid}`);
          if (targetCrumbUuid !== null) {
            fileManagerStore.navigateToFolder(targetCrumbUuid);
          } else {
            console.warn('[FileManagerView Timer CB] Attempted to navigate to null UUID.');
          }
        }
        openFolderTimerId.value = null;
        hoveredCrumbUuid.value = null;
      }, BREADCRUMB_HOVER_DELAY);
      console.log(`[FileManagerView handleZoneDragOver] Timer started: ${openFolderTimerId.value}`);
    }
  } else {
    // Not hovering a valid target (or hovering current folder/root)
    if (hoveredCrumbUuid.value !== null) {
      console.log(`[FileManagerView handleZoneDragOver] Left valid crumb target (was ${hoveredCrumbUuid.value}). Clearing timer.`);
      clearOpenFolderTimer();
    }
  }
};

// --- Watcher to clear timer when leaving the drop zone ---
watch(isOverDropZone, (isOver) => {
  if (!isOver) {
    console.log('[FileManagerView Watch isOverDropZone] Left drop zone. Clearing timer.');
    clearOpenFolderTimer();
  }
});

// --- Attach dragover listener using native DOM API in CAPTURE phase ---

onMounted(async () => {
  console.log('[FileManagerView onMounted] Attaching native dragover listener to document.body (CAPTURE PHASE).');
  // Add the native listener with capture: true
  document.body.addEventListener('dragover', handleZoneDragOver, { capture: true });

  // Keep global dragend listener
  console.log('[FileManagerView onMounted] Adding global dragend listener.');
  window.addEventListener('dragend', handleGlobalDragEnd);

  // Keep resize listener
  console.log('[FileManagerView onMounted] Adding resize listener.');
  window.addEventListener('resize', updateSpotlightPosition);

  console.log('[FileManagerView LifeCycle] === onMounted START ===');

  // Wait for the next DOM update cycle, hoping Pinia hydration is done
  await nextTick();
  console.log('[FileManagerView onMounted - after nextTick] Starting navigation logic...');

  const storeFolderId = fileManagerStore.currentFolderId;
  const shouldRemember = settingsStore.rememberLastFolder;
  console.log(`[FileManagerView onMounted - after nextTick] Checking state. Current store folderId: ${storeFolderId}, Should remember: ${shouldRemember}`);

  // Decide initial navigation target based on setting
  let targetFolderId: string | null;
  if (shouldRemember) {
    console.log(`[FileManagerView onMounted - after nextTick] Remembering last folder. Target is persisted ID: ${storeFolderId}`);
    targetFolderId = storeFolderId; // Use persisted ID
  } else {
    console.log(`[FileManagerView onMounted - after nextTick] NOT remembering last folder. Forcing target to ROOT.`);
    targetFolderId = null; // Force root
  }

  // Check if navigation is actually needed (avoid redundant navigation if already at target)
  // Also check if items are empty, might need initial load even if ID matches
  if (fileManagerStore.currentFolderId !== targetFolderId || currentItems.value.length === 0) {
    console.log(`[FileManagerView onMounted - after nextTick] Current folder (${fileManagerStore.currentFolderId}) differs from target (${targetFolderId}) or items empty. Calling navigateToFolder.`);
    await fileManagerStore.navigateToFolder(targetFolderId);
    console.log(`[FileManagerView onMounted - after nextTick] navigateToFolder for ${targetFolderId} finished.`);
  } else {
    console.log(`[FileManagerView onMounted - after nextTick] Already at target folder (${targetFolderId}) with items loaded. Skipping navigateToFolder call.`);
  }

  console.log('[FileManagerView LifeCycle] === onMounted END ===');
});

// Ensure listener is removed on unmount
onUnmounted(() => {
  console.log('[FileManagerView onUnmounted] Removing global dragend listener.');
  window.removeEventListener('dragend', handleGlobalDragEnd);
  // Clean up the native body listener with capture: true
  console.log('[FileManagerView onUnmounted] Removing native document.body dragover listener (CAPTURE PHASE).');
  document.body.removeEventListener('dragover', handleZoneDragOver, { capture: true });

  // Clean up resize listener
  console.log('[FileManagerView onUnmounted] Removing resize listener.');
  window.removeEventListener('resize', updateSpotlightPosition);

  clearOpenFolderTimer();
  console.log('[FileManagerView LifeCycle] === onUnmounted END ===');
});

// Global handler to clean up state if drag ends anywhere
const handleGlobalDragEnd = (event: DragEvent) => {
  console.log('[FileManagerView handleGlobalDragEnd] Drag operation ended globally.');
  clearOpenFolderTimer();
};

// Add onUpdated hook
onUpdated(() => {
  console.log('[FileManagerView LifeCycle] === onUpdated ===');
  // Log state that might cause updates
  console.log(`[FileManagerView onUpdated] currentItems count: ${currentItems.value.length}`);
  console.log(`[FileManagerView onUpdated] editingItemId: ${editingItemId.value}`);
});

// Add detailed onBeforeUnmount logging
onBeforeUnmount(() => {
  console.warn('[FileManagerView LifeCycle] >>> onBeforeUnmount triggered <<< START');
  console.log(`[FileManagerView onBeforeUnmount] Current Route Path: ${router.currentRoute.value.path}`);
  console.log(`[FileManagerView onBeforeUnmount] Current Route Name: ${router.currentRoute.value.name?.toString() ?? 'N/A'}`);
  console.log(`[FileManagerView onBeforeUnmount] File Manager Store - Current Folder ID: ${fileManagerStore.currentFolderId}`);
  console.log(`[FileManagerView onBeforeUnmount] File Manager Store - Items count: ${currentItems.value.length}`);
  console.log(`[FileManagerView onBeforeUnmount] File Manager Store - isLoading: ${isLoading.value}`);
  console.log(`[FileManagerView onBeforeUnmount] File Manager Store - Error: ${fileManagerStore.error}`);
  console.log('[FileManagerView onBeforeUnmount] --- Interaction State ---');
  console.log(`[FileManagerView onBeforeUnmount] Selected Item ID: ${selectedItemId.value}`);
  console.log(`[FileManagerView onBeforeUnmount] Editing Item ID: ${editingItemId.value}`);
  console.log(`[FileManagerView onBeforeUnmount] Focus Ghost Item ID: ${focusGhostItemId.value}`);
  console.log('[FileManagerView onBeforeUnmount] Investigating potential causes: route changes, v-if conditions, programmatic unmount.');

  // --- Add cleanup logic here ---
  if (editingItemId.value) {
    console.warn('[FileManagerView onBeforeUnmount] Clearing editingItemId to hide rename overlay.');
    ElMessage.warning('因为导航离开页面，已取消当前重命名操作。'); // Add user warning
    editingItemId.value = null;
    // Optionally call cancelRename if other cleanup is needed in composable
    // cancelRename();
  }
  // -----------------------------

  // Add a breakpoint trigger if needed for debugging
  // debugger;
  console.warn('[FileManagerView LifeCycle] >>> onBeforeUnmount triggered <<< END');
});

// Watch for currentItems changes to trigger editing automatically for newly created folders
watch(() => fileManagerStore.currentItems, (newItems, oldItems) => {
  console.log(`[DEBUG FileManagerView Watch currentItems] Triggered. newlyCreatedFolderId: ${newlyCreatedFolderId.value}`);
  if (newlyCreatedFolderId.value) {
    const targetUuid = newlyCreatedFolderId.value; // Use captured ID
    const newItem = newItems.find(item => item.uuid === targetUuid);
    console.log(`[DEBUG FileManagerView Watch currentItems] Searching for newItem with UUID: ${targetUuid}. Found:`, !!newItem);
    if (newItem) {
      console.log(`[DEBUG FileManagerView Watch currentItems] Found newly created folder item: ${newItem.name}. Calling startRename...`);
      const idBeforeRename = newlyCreatedFolderId.value;
      // Call the local wrapper startRename to ensure logs
      startRename(newItem);
      console.log(`[DEBUG FileManagerView Watch currentItems] Called startRename for ${idBeforeRename}. Resetting newlyCreatedFolderId.`);
      newlyCreatedFolderId.value = null; // Reset the flag *after* calling startRename
    } else {
      console.log(`[DEBUG FileManagerView Watch currentItems] Newly created folder ID ${targetUuid} set, but item not found in new list yet.`);
      // Resetting the flag here might be problematic if the item appears later due to async issues
      // Consider moving the reset inside the 'if (newItem)' block if problems persist
      // newlyCreatedFolderId.value = null;
    }
  }
}, {deep: true});

// Watch for context menu closing to set focus ghost
watch(() => contextMenu.show, (newValue, oldValue) => {
  console.log(`[FileManagerView Watch] contextMenu.show changed from ${oldValue} to ${newValue}`);
  if (oldValue === true && newValue === false) {
    // Menu just closed
    const closedTargetId = contextMenu.targetItem?.uuid; // Get ID before clearing
    console.log(`[FileManagerView Watch] Context menu closed for target: ${closedTargetId}. Editing ID: ${editingItemId.value}`);
    if (closedTargetId) {
      // Only apply focus ghost if NOT entering rename mode for this item
      if (editingItemId.value !== closedTargetId) {
        // selectedItemId.value = null; // Let interaction composable handle selection state
        // Apply focus ghost
        focusGhostItemId.value = closedTargetId;
        console.log(`[FileManagerView Watch] Applying focus ghost to: ${closedTargetId}`);
      } else {
        console.log(`[FileManagerView Watch] Menu closed, but entering rename mode for ${closedTargetId}. Skipping focus ghost.`);
        // Keep selectedItemId as set by startRename
      }
    }
    // Clean up menu state
    console.log('[FileManagerView Watch] Cleaning up context menu state.');
    contextMenu.targetItem = null;
    contextMenu.x = 0;
    contextMenu.y = 0;

    // Ensure any lingering pending state is cleared (belt and suspenders)
    if (contextMenuTimeoutId.value) {
      console.log('[FileManagerView Watch] Clearing lingering context menu timeout.');
      clearTimeout(contextMenuTimeoutId.value);
      contextMenuTimeoutId.value = null;
    }
    contextMenuPendingTargetId.value = null;
  }
});

// --- Spotlight Update Logic (Moved Before Watcher) ---
const updateSpotlightPosition = () => {
  console.log(`[DEBUG FileManagerView updateSpotlightPosition] Called. isRenamingActive: ${isRenamingActive.value}, overlayRef:`, !!overlayRef.value);
  // Only run if overlay exists and renaming is active
  if (!overlayRef.value || !isRenamingActive.value) {
    console.log('[DEBUG FileManagerView updateSpotlightPosition] Exiting: Not renaming or overlay not ready.');
    // Ensure spotlight is hidden if not renaming
    if (overlayRef.value) {
      console.log('[DEBUG FileManagerView updateSpotlightPosition] Hiding spotlight.');
      overlayRef.value.style.setProperty('--spotlight-x', `50%`);
      overlayRef.value.style.setProperty('--spotlight-y', `50%`);
      overlayRef.value.style.setProperty('--target-spotlight-radius', `0px`);
    }
    return;
  }

  const canvas = textMeasureCanvasRef.value;
  const ctx = canvas?.getContext('2d');
  // Get the input instance via the template ref array
  const inputInstance = (nameInputRef.value && nameInputRef.value.length > 0) ? nameInputRef.value[0] : null;
  // Get the actual HTML input element from the instance
  const inputElement = inputInstance?.$el?.querySelector('input') as HTMLInputElement | null;
  const overlay = overlayRef.value;

  console.log(`[DEBUG FileManagerView updateSpotlightPosition] Refs check: canvas: ${!!canvas}, ctx: ${!!ctx}, inputInstance: ${!!inputInstance}, inputElement: ${!!inputElement}`);

  if (inputElement && canvas && ctx) {
    // Get input dimensions and position
    const rect = inputElement.getBoundingClientRect();
    // Get computed font style for accurate text measurement
    const computedStyle = window.getComputedStyle(inputElement);
    const font = computedStyle.font;
    ctx.font = font;
    // Measure the current text in the input
    const textToMeasure = editingNameModel.value || '';
    const textMetrics = ctx.measureText(textToMeasure);
    const measuredWidth = textMetrics.width;
    // Calculate the center of the measured text within the viewport
    const viewportCenterX = rect.left + measuredWidth / 2;
    const viewportCenterY = rect.top + rect.height / 2;
    // Calculate viewport dimensions and desired spotlight offset
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;
    const offsetX = viewportWidth * 0.10;
    const offsetY = viewportHeight * 0.10;
    // Final spotlight position with offset
    const finalSpotlightX = viewportCenterX + offsetX;
    const finalSpotlightY = viewportCenterY + offsetY;
    // Calculate dynamic spotlight radius based on text length
    const textLength = editingNameModel.value?.length || 0;
    const baseRadius = 50;
    const growthFactor = 1.5;
    const dynamicRadius = Math.pow(textLength, growthFactor);
    const finalRadius = Math.max(baseRadius, baseRadius + dynamicRadius);

    console.log(`[DEBUG FileManagerView updateSpotlightPosition] Calculated: X=${finalSpotlightX.toFixed(1)}, Y=${finalSpotlightY.toFixed(1)}, R=${finalRadius.toFixed(1)}, Text="${textToMeasure}"`);

    // Apply calculated styles to the overlay using CSS variables
    overlay.style.setProperty('--spotlight-x', `${finalSpotlightX}px`);
    overlay.style.setProperty('--spotlight-y', `${finalSpotlightY}px`);
    overlay.style.setProperty('--target-spotlight-radius', `${finalRadius}px`);

  } else {
    console.warn('[DEBUG FileManagerView updateSpotlightPosition] Fallback: Input element or canvas context not found. Centering spotlight.');
    // Fallback if input element or canvas context not found
    overlay.style.setProperty('--spotlight-x', `50%`);
    overlay.style.setProperty('--spotlight-y', `50%`);
    overlay.style.setProperty('--target-spotlight-radius', `80px`); // Default target radius
  }
};

// Watch for changes in editing state and input value to update spotlight position reactively.
// This ensures the spotlight follows the input and appears/disappears correctly.
watchEffect(() => {
  console.log(`[DEBUG FileManagerView watchEffect for Spotlight] Triggered. isRenamingActive: ${isRenamingActive.value}, editingNameModel: ${editingNameModel.value}`);
  // Trigger update whenever dependencies change (isRenamingActive, editingNameModel etc.)
  // The actual calculation is now in the separate function
  updateSpotlightPosition();
  // No else needed, overlay is hidden when not active via v-if="isRenamingActive"
});

// Watch editingItemId for logging changes
watch(editingItemId, (newId, oldId) => {
  console.log(`[DEBUG FileManagerView Watch editingItemId] Changed from ${oldId} to ${newId}`);
});

// Watch editingNameModel for logging changes
watch(editingNameModel, (newValue, oldValue) => {
  console.log(`[DEBUG FileManagerView Watch editingNameModel] Changed from "${oldValue}" to "${newValue}"`);
});

// --- Dialog Logic (Actions updated below) ---
const resetDialog = () => {
  console.log('[FileManagerView resetDialog] Resetting dialog form.');
  dialogForm.name = '';
  renameTarget.value = null;
  dialogFormRef.value?.resetFields();
};

const showCreateFileDialog = () => {
  console.log('[FileManagerView showCreateFileDialog] Opening create file dialog.');
  resetDialog();
  dialogMode.value = 'createFile';
  dialogForm.name = '新文件.xml'; // Default name
  dialogVisible.value = true;
  nextTick(() => {
    console.log('[FileManagerView showCreateFileDialog] nextTick: Clearing validation.');
    dialogFormRef.value?.clearValidate('name');
  });
};

const showRenameDialog = (item: FilesystemItemMeta) => {
// Add console log for debugging
  console.log(`[FileManagerView showRenameDialog] Opening rename dialog for item: ${JSON.stringify(item)}`);
  resetDialog();
  dialogMode.value = item.type === 'folder' ? 'renameFolder' : 'renameFile';
  renameTarget.value = item;
  dialogForm.name = item.name;
  dialogVisible.value = true;
  console.log('[FileManagerView showRenameDialog] dialogVisible set to:', dialogVisible.value);
  nextTick(() => {
    console.log('[FileManagerView showRenameDialog] nextTick: dialogFormRef available? Clearing validation.', !!dialogFormRef.value);
    dialogFormRef.value?.clearValidate('name');
  });
};

// submitDialog now calls fileManagerStore actions
const submitDialog = async () => {
  console.log(`[FileManagerView submitDialog] Attempting submit. Mode: ${dialogMode.value}, Target: ${renameTarget.value?.uuid}`);
  if (!dialogFormRef.value) {
    console.warn('[FileManagerView submitDialog] Form ref not available.');
    return;
  }
  await dialogFormRef.value.validate(async (valid) => {
    if (valid) {
      console.log('[FileManagerView submitDialog] Form valid. Setting loading state.');
      isDialogLoading.value = true;
      let operationSuccess = false; // Flag to track if the operation succeeded
      try {
        if (renameTarget.value) { // Check if renaming
          console.log(`[FileManagerView submitDialog] Calling store renameItem for ${renameTarget.value.uuid} to ${dialogForm.name}`);
          await fileManagerStore.renameItem(renameTarget.value.uuid, dialogForm.name, renameTarget.value.type === 'folder');
          console.log('[FileManagerView submitDialog] store renameItem successful.');
          operationSuccess = true; // Mark rename as successful
        } else if (dialogMode.value === 'createFile') {
          console.log(`[FileManagerView submitDialog] Calling store action to create file: ${dialogForm.name}`);
          const newFileMeta = await fileManagerStore.createFileAndLoad(dialogForm.name);
          if (newFileMeta && newFileMeta.uuid) {
            console.log(`[FileManagerView submitDialog] File created, navigating to editor for UUID: ${newFileMeta.uuid}`);
            // Navigate AFTER marking success and potentially closing dialog
            operationSuccess = true; // Mark file creation as successful
            // Decide UX: Close dialog THEN navigate, or navigate then close?
            // Closing first seems safer.
            dialogVisible.value = false;
            router.push({name: 'Editor'}); // Navigate after closing
          } else {
            // Error message handled by the store action
            console.error('[FileManagerView submitDialog] File creation in store failed or returned null.');
            // Keep the dialog open by letting the error propagate
            // operationSuccess remains false
          }
        }

        // Close dialog ONLY if an operation succeeded AND we didn't already close it
        // (like in the createFile success path)
        if (operationSuccess && dialogVisible.value) {
          console.log('[FileManagerView submitDialog] Operation successful (e.g., rename). Closing dialog.');
          dialogVisible.value = false;
        }

      } catch (error: any) {
        console.error(`[FileManagerView submitDialog] Error during dialog submit (${dialogMode.value}):`, error);
        // Keep the dialog open on error, operationSuccess remains false
      } finally {
        console.log('[FileManagerView submitDialog] Resetting loading state.');
        isDialogLoading.value = false;
      }
    } else {
      console.warn('[FileManagerView submitDialog] Form validation failed.');
    }
  });
};

// --- File/Folder Actions (Updated) ---

const triggerFileUpload = () => {
  console.log('[FileManagerView triggerFileUpload] Triggering file input click.');
  fileInput.value?.click();
};

// handleFileUpload calls saveNewFileFromUpload
const handleFileUpload = async (event: Event) => {
  console.log('[FileManagerView handleFileUpload] File input changed.');
  const target = event.target as HTMLInputElement;
  if (target.files && target.files[0]) {
    const file = target.files[0];
    console.log(`[FileManagerView handleFileUpload] File selected: ${file.name}`);
    try {
      ElMessage.info(`正在上传并保存文件 ${file.name}...`);
      // Call fileManagerStore action for uploads
      await fileManagerStore.saveNewFileFromUpload(file);
      console.log(`[FileManagerView handleFileUpload] saveNewFileFromUpload successful for ${file.name}`);
      // Success message handled within the store action
      if (fileInput.value) {
        fileInput.value.value = ''; // Reset input
      }
    } catch (error) {
      console.error('[FileManagerView handleFileUpload] Error uploading file:', error);
      // Error message handled within the store action
    }
  } else {
    console.warn('[FileManagerView handleFileUpload] No file selected.');
  }
};

// loadFile calls loadFileIntoEditor
const loadFile = async (uuid: string) => {
  console.log(`[FileManagerView loadFile] Attempting to load file ${uuid} into editor.`);
  try {
    ElMessage.info('正在加载文件到编辑器...');
    // Call the coordinating action in fileManagerStore
    await fileManagerStore.loadFileIntoEditor(uuid);
    console.log(`[FileManagerView loadFile] loadFileIntoEditor successful for ${uuid}. Navigating to editor.`);
    // Success message handled by the load process (editorStore/fileManagerStore)
    // Navigate to editor view after successful load attempt
    router.push({name: 'Editor'});
  } catch (error) {
    console.error(`[FileManagerView loadFile] Error loading file ${uuid} into editor:`, error);
    // Error message handled by loadFileIntoEditor
  }
};

// deleteFile calls fileManagerStore action
const deleteFile = async (uuid: string, name: string) => {
  console.log(`[FileManagerView deleteFile] Attempting to delete file ${uuid} (${name}).`);
  try {
    // Confirmation dialog remains here for immediate feedback
    console.log(`[FileManagerView deleteFile] Showing confirmation dialog for ${name}.`);
    await ElMessageBox.confirm(
        `确定要删除文件 "${name}" 吗？此操作无法撤销。`,
        '确认删除',
        {
          confirmButtonText: '删除',
          cancelButtonText: '取消',
          type: 'warning',
        }
    );
    console.log(`[FileManagerView deleteFile] Deletion confirmed for ${name}. Calling store action.`);
    // Call fileManagerStore action
    await fileManagerStore.deleteStoredFile(uuid);
    console.log(`[FileManagerView deleteFile] Store action successful for ${name}.`);
    ElMessage.success(`文件 "${name}" 已删除。`); // Keep success message here as confirmation is local

    // Check if the deleted file was the one loaded in the editor (needs editorStore access)
    // This logic might need to move to the store action or be handled via event/callback
    // const editorStore = useEditorStore(); // Hypothetical access
    // if (editorStore.currentFileInfo.uuid === uuid) {
    //     editorStore.clearEditorState();
    //     ElMessage.info("编辑器中加载的文件已被删除，已清空编辑器。");
    // }

  } catch (error) {
    if (error !== 'cancel' && error !== 'close') {
      console.error(`[FileManagerView deleteFile] Error deleting file ${name}:`, error);
      // Error message handled by store action, but keep local feedback for cancellation
      // ElMessage.error(`删除文件 "${name}" 失败: ${error instanceof Error ? error.message : '未知错误'}`);
    } else {
      console.log(`[FileManagerView deleteFile] Deletion cancelled for ${name}.`);
      ElMessage.info('删除操作已取消。');
    }
  }
};

// deleteFolder calls fileManagerStore action
const deleteFolder = async (uuid: string, name: string) => {
  // Confirmation is now handled inside the store action based on settings
  console.log(`[FileManagerView deleteFolder] Attempting to delete folder ${uuid} (${name}). Calling store action...`);
  try {
    // Call fileManagerStore action, passing name for potential confirmation message
    await fileManagerStore.deleteStoredFolder(uuid, name);
    console.log(`[FileManagerView deleteFolder] Store action successful for ${name}.`);
    // Success/Cancellation messages handled within the store action
  } catch (error) {
    if (error !== 'cancel' && error !== 'close') {
      console.error(`[FileManagerView deleteFolder] Error deleting folder ${name}:`, error);
      // Error message should be handled by the store action
      // ElMessage.error(fileManagerStore.error || `删除文件夹 "${name}" 失败: ${error instanceof Error ? error.message : '未知错误'}`);
    }
    // Cancellation message handled within the store action if confirmation was shown
  }
};

// downloadFile calls fileManagerStore action
const downloadFile = async (uuid: string, filename: string) => {
  console.log(`[FileManagerView downloadFile] Preparing to download file ${uuid} (${filename}).`);
  ElMessage.info(`准备下载文件 ${filename}...`);
  try {
    // Call fileManagerStore action to get data
    const fileData = await fileManagerStore.getFileDataForDownload(uuid);
    if (!fileData || typeof fileData.content !== 'string') {
      console.error(`[FileManagerView downloadFile] Failed to get file data for ${filename}.`);
      // Error message handled by store action if fileData is null
      // ElMessage.error(`下载失败：无法获取文件内容 (${filename})。`);
      return;
    }
    console.log(`[FileManagerView downloadFile] File data received for ${filename}. Creating blob.`);
    // Blob creation and download link logic remains the same
    const blob = new Blob([fileData.content], {type: 'application/xml;charset=utf-8'});
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = filename;
    document.body.appendChild(link);
    console.log(`[FileManagerView downloadFile] Triggering download for ${filename}.`);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
    ElMessage.success(`文件 ${filename} 已开始下载。`);

  } catch (error: any) {
    console.error(`[FileManagerView downloadFile] Error downloading ${filename}:`, error);
    // Error should be handled by store action
    // ElMessage.error(fileManagerStore.error || `下载文件 ${filename} 失败: ${error.message || '未知错误'}`);
  }
};


// --- Formatting (Keep as is) ---
const formatDate = (dateValue: string | number | Date | undefined | null): string => {
  if (dateValue === null || dateValue === undefined || dateValue === '') return '-';
  try {
    const date = new Date(dateValue);
    if (isNaN(date.getTime())) {
      console.warn('[FileManagerView formatDate] Could not parse date value:', dateValue);
      return 'Invalid Date';
    }
    return date.toLocaleString();
  } catch (error) {
    console.error('[FileManagerView formatDate] Error formatting date:', dateValue, error);
    return 'Error';
  }
};


// --- Row Handling (Updated) ---
// NOTE: handleItemDoubleClick in composable now handles this logic
/*
const handleRowDoubleClick = (row: FilesystemItemMeta) => {
  console.log(`[FileManagerView handleRowDoubleClick] Double clicked on ${row.type}: ${row.name}`);
  // If double-clicking while somehow in edit mode for this item, cancel edit first.
  if (row.uuid === editingItemId.value) {
    console.log('[FileManagerView handleRowDoubleClick] Was editing, cancelling rename first.');
    cancelRename();
  }

  if (row.type === 'folder') {
    // Use navigateTo action (which calls store action)
    console.log(`[FileManagerView handleRowDoubleClick] Navigating to folder ${row.uuid}.`);
    navigateTo(row.uuid);
  }
  if (row.type === 'file') {
    // Use loadFile action (which calls store action)
    console.log(`[FileManagerView handleRowDoubleClick] Loading file ${row.uuid}.`);
    loadFile(row.uuid);
  }
};
*/

// --- Breadcrumb Navigation (Updated) ---
// navigateTo now directly calls the store action
const navigateTo = (folderId: string | null) => {
  console.log(`[FileManagerView navigateTo] Navigating to folder ${folderId}. Calling store action.`);
  fileManagerStore.navigateToFolder(folderId);
};

// --- Move Dialog Logic (Actions updated) ---
// showMoveDialog calls fileManagerStore action
const showMoveDialog = async (item: FilesystemItemMeta) => {
  console.log(`[FileManagerView showMoveDialog] Opening move dialog for item ${item.uuid} (${item.name})`);
  itemToMove.value = item;
  selectedTargetFolderId.value = null;
  isMoveDialogLoading.value = true;
  moveDialogVisible.value = true;
  try {
    // Call fileManagerStore action to get folders
    console.log(`[FileManagerView showMoveDialog] Calling store getAllFolders.`);
    allFolders.value = await fileManagerStore.getAllFolders();
    console.log(`[FileManagerView showMoveDialog] Fetched ${allFolders.value.length} folders for move dialog.`);
  } catch (error) {
    // Error handled by store action's message
    console.error("[FileManagerView showMoveDialog] Error fetching folders:", error);
    moveDialogVisible.value = false;
  } finally {
    isMoveDialogLoading.value = false;
  }
};

// submitMoveDialog calls fileManagerStore action
const submitMoveDialog = async () => {
  console.log(`[FileManagerView submitMoveDialog] Attempting to move item ${itemToMove.value?.uuid} to target ${selectedTargetFolderId.value}`);
  if (!itemToMove.value) {
    console.error("[FileManagerView submitMoveDialog] Error: itemToMove is null.");
    ElMessage.error("内部错误：未指定要移动的项目。");
    return;
  }
  if (selectedTargetFolderId.value === undefined) {
    console.warn("[FileManagerView submitMoveDialog] No target folder selected.");
    ElMessage.warning("请选择目标文件夹");
    return;
  }

  // UI checks remain useful
  if (itemToMove.value.parentId === selectedTargetFolderId.value) {
    console.log("[FileManagerView submitMoveDialog] Item already in target folder.");
    ElMessage.info("项目已在目标文件夹中。无需移动。");
    moveDialogVisible.value = false;
    return;
  }
  if (itemToMove.value.type === 'folder' && itemToMove.value.uuid === selectedTargetFolderId.value) {
    console.error("[FileManagerView submitMoveDialog] Attempting to move folder into itself.");
    ElMessage.error("无法将文件夹移动到其自身内部。");
    return;
  }

  console.log("[FileManagerView submitMoveDialog] Calling store moveItem action.");
  isMoveDialogLoading.value = true;
  try {
    // Call fileManagerStore action
    await fileManagerStore.moveItem(
        itemToMove.value.uuid,
        selectedTargetFolderId.value, // Can be null for root
        itemToMove.value.type === 'folder'
    );
    console.log("[FileManagerView submitMoveDialog] Store moveItem action successful.");
    // Success message handled by store action
    moveDialogVisible.value = false;
  } catch (error: any) {
    // Error message handled by store action
    console.error("[FileManagerView submitMoveDialog] Error during move:", error);
  } finally {
    isMoveDialogLoading.value = false;
  }
};

// Computed property for dialog title remains the same
const moveDialogTitle = computed(() => {
  return `移动 '${itemToMove.value?.name || ""}' 到...`;
});

// --- Create Folder Click Handler --- added
const handleCreateFolderClick = async () => {
  console.log("[FileManagerView handleCreateFolderClick] Create Folder button clicked.");
  const newFolderMeta = await fileManagerStore.createTemporaryFolder();
  if (newFolderMeta) {
    // Store the ID to trigger editing when the list updates
    newlyCreatedFolderId.value = newFolderMeta.uuid;
    console.log(`[FileManagerView handleCreateFolderClick] Temporary folder created, waiting for list update to start editing ${newFolderMeta.uuid}`);
  } else {
    console.error("[FileManagerView handleCreateFolderClick] createTemporaryFolder failed.");
  }
};

// --- Helper to format item type ---
const formatType = (item: FilesystemItemMeta): string => {
  if (item.type === 'folder') {
    return '文件夹';
  } else {
    // Basic file type based on extension (can be expanded)
    const extension = item.name.split('.').pop()?.toLowerCase();
    if (extension === 'xml') {
      return 'XML 文件';
    } else if (extension === 'jdf') {
      return 'JDF 文件';
    } else {
      // You might want to map other extensions here
      return extension ? `${extension.toUpperCase()} 文件` : '文件'; // Generic file or EXT 文件
    }
  }
};

// --- Helper to format size ---
const formatSize = (sizeInBytes: number | undefined | null): string => {
  // Handle folder size specifically - maybe don't show for folders?
  // Or rely on the calculated size being present.
  // For now, treat 0 or undefined/null the same for display.
  if (sizeInBytes === null || sizeInBytes === undefined || sizeInBytes < 0) {
    return '--'; // Indicate unavailable or invalid size
  }
  // Don't show 0 B for folders, maybe show -- ?
  // Let's keep 0 B for files for now.
  // if (sizeInBytes === 0) return '--';
  if (sizeInBytes === 0) return '0 B';

  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; // Added more units
  let i = Math.max(0, Math.floor(Math.log(sizeInBytes) / Math.log(k)));

  // Handle potential edge case where i might be out of bounds
  if (i >= sizes.length) {
    i = sizes.length - 1;
  }

  // Format with one decimal place for KB and above, 0 for Bytes
  const formattedSize = parseFloat((sizeInBytes / Math.pow(k, i)).toFixed(i === 0 ? 0 : 1));

  return `${formattedSize} ${sizes[i]}`;
};

// --- Sorting Handler ---
/**
 * Handles clicks on the simulated header items to trigger sorting.
 * @param key The sort key ('name', 'type', 'size', 'lastModified')
 */
const handleSort = (key: SortKey) => {
  console.log(`[FileManagerView handleSort] Clicked header for key: ${key}`);
  fileManagerStore.setSort(key); // Call the store action
};
// ---------------------

console.log('[FileManagerView] Script setup execution end.');

</script>


<!-- Styles remain the same -->
<style lang="scss" scoped>
// --- Keyframes for Animations ---
@keyframes spotlight-appear-bounce {
  0% {
    opacity: 0;
    transform: scale(0.5);
  }
  60% {
    opacity: 1;
    transform: scale(1.1); /* Overshoot for bounce */
  }
  100% {
    opacity: 1;
    transform: scale(1); /* Settle */
  }
}

@keyframes spotlight-disappear-expand-fade { /* Reverse bounce effect - expand out */
  0% {
    opacity: 1;
    transform: scale(1);
  }
  40% { /* Bounce outwards */
    /* Overshoot slightly while fading */
    opacity: 1; /* Stay opaque */
    transform: scale(1.15);
  }
  100% {
    /* Quickly shrink and fade out */
    opacity: 0;
    transform: scale(5); /* Expand significantly while fading at the end */
  }
}


// --- Semantic Variables for File Item States ---
// Define semantic variables here to improve readability and maintainability.
// These map specific interaction states to Element Plus color variables.
// Define variables on the component's root class for proper scoping.
.file-manager-view {
  // -- Focused State (Item actively selected) --
  --fm-item-bg-focused: var(--el-color-primary-light-8); // Background color when item is focused
  --fm-item-border-focused: var(--el-color-primary-dark-2); // Border color when item is focused (deeper color)

  // -- Hover State (Mouse over item, but not focused) --
  // Use RGBA for slight transparency, derived from el-color-primary-light-9
  --fm-item-bg-hover: rgba(var(--el-color-primary-light-9-rgb), 0.1);

  // -- Renaming State --
  // Visually similar to focused state by default
  --fm-item-bg-renaming: var(--fm-item-bg-focused); // Background matches focused state
  --fm-item-border-renaming: var(--fm-item-border-focused); // Default border matches focused state
  // Specific border color when hovering the *input* during rename
  --fm-item-border-renaming-input-hover: var(--el-color-primary-light-3); // Lighter border for input hover feedback
  // Border color for the input element itself during rename
  --fm-input-border-renaming: var(--fm-item-border-focused); // Input border matches the dark item border

  // -- Focus Ghost State (Item was focused, then clicked outside) --
  --fm-item-bg-ghost: transparent; // No background for ghost state
  --fm-item-border-ghost: var(--fm-item-border-focused); // Border matches focused state to indicate last focus

  // -- Context Menu Active State --
  // Style for the item whose context menu is currently shown
  --fm-item-bg-context-active: var(--el-color-info-light-9); // Grayish background
  --fm-item-border-context-active: transparent; // No border
}

// --- Base Styles ---
.file-manager-view {
  // Add padding or other overall container styles if needed
  padding: 15px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.breadcrumb-nav {
  // Styles for breadcrumbs if needed
}

.actions {
  display: flex;
  gap: 10px; // Spacing between action buttons
}

// --- List Styles ---
.simple-list-container {
  margin-top: 15px; // Add some space above the list
}

.filesystem-item-li {
  border: 1px solid transparent;
  position: relative;
  transition: background-color 0.1s ease, border-color 0.1s ease;
  display: flex;
  align-items: center;
  height: 39px;
  box-sizing: border-box;
  border-radius: 4px;
  margin-bottom: 2px;
  overflow: hidden;

  &:hover {
    // Use the semantic variable for hover background
    background-color: var(--fm-item-bg-hover);
  }

  // -- Focused State Styling --
  &.is-focused {
    background-color: var(--fm-item-bg-focused);
    border-color: var(--fm-item-border-focused);
    border-width: 1px;
  }

  // -- Renaming State Styling --
  &.is-renaming {
    // Base renaming style matches focused state
    background-color: var(--fm-item-bg-renaming);
    border-color: var(--fm-item-border-renaming); // Default border
    border-width: 1px;
    border-style: solid;

    // When hovering the list item *but not* the input field itself: Light border
    &:hover:not(.is-renaming-input-hover) {
      border-color: var(--fm-item-border-renaming-input-hover); // Use the specific lighter border
    }

    // Style the input element itself within a renaming item
    :deep(.el-input__wrapper) {
      // Match the input border color to the semantic variable
      box-shadow: 0 0 0 1px var(--fm-input-border-renaming) inset;
      // Keep the same border color even when the input is focused internally
      &.is-focus {
        // Use !important carefully, necessary here to override Element Plus focus styles
        box-shadow: 0 0 0 1px var(--fm-input-border-renaming) inset !important;
      }
    }

    // Apply pulsing box-shadow animation specifically to the wrapper during rename
    &.name-input :deep(.el-input__wrapper) {
    }
  }

  // -- Focus Ghost State Styling --
  &.is-focus-ghost {
    background-color: var(--fm-item-bg-ghost); // Transparent background
    border-color: var(--fm-item-border-ghost); // Use the ghost border color (same as focused)
    border-width: 1px;
  }

  // -- Context Menu Active State Styling --
  // Applied when the context menu for this item is visible
  &.is-context-menu-active {
    background-color: var(--fm-item-bg-context-active);
    border-color: var(--fm-item-border-context-active);

    // When hovering the item while its context menu is active, revert to focused style
    &:hover {
      background-color: var(--fm-item-bg-focused); // Use focused background
      border-color: var(--fm-item-border-focused); // Use focused border
    }
  }
}

.item-content {
  display: grid;
  // Change first gap column to 5px
  grid-template-columns: 24px 5px 1fr 45px 80px 45px 70px 45px 120px;
  /* column-gap: 20px; */ /* Remove column-gap */
  align-items: center;
  width: 100%;
  box-sizing: border-box;
  overflow: hidden; /* Keep internal overflow hidden */
  padding: 10px 12px;
  cursor: pointer;
}

.item-icon {
  grid-column: 1; /* Place icon in the first column */
}

.item-name {
  grid-column: 3; /* Place name in the third column (after 8px gap) */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 100px;
  text-align: left;
}

.item-type,
.item-size {
  font-size: 0.9em;
  color: var(--el-text-color-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
  /* margin-left: 35px; */ /* Removed */
}

.item-type {
  grid-column: 5; /* Place type in the fifth column (after 45px gap) */
}

.item-size {
  grid-column: 7; /* Place size in the seventh column (after 45px gap) */
  justify-self: end;
  text-align: right;
}

.item-modified {
  grid-column: 9; /* Place date in the ninth column (after 45px gap) */
  font-size: 0.9em;
  color: var(--el-text-color-secondary);
  position: static;
  justify-self: end;
  text-align: right;
  white-space: nowrap;
  /* margin-left: 35px; */ /* Removed */
}

// --- Ensure input spans correctly during rename ---
.name-input {
  // Grid specific: Make input span ONLY the name column (column 3)
  grid-column: 3; /* Now column 3 is the name column */
  align-self: center;
  min-width: 150px;
  max-width: 450px;
  :deep(.el-input__inner) {
    font-size: 16px !important;
    line-height: normal;
    letter-spacing: inherit;
    font-family: inherit;
  }
}

// --- Dialog Styles (Optional) ---
.dialog-footer {
  // Add styles if needed
}

// --- Custom Context Menu Item Styles ---
// Styles for items rendered via the #itemRender slot
.custom-context-menu-item {
  display: flex;
  align-items: center;
  padding: 6px 12px; // Adjust padding as needed
  cursor: pointer;
  user-select: none;
  white-space: nowrap;

  &:hover {
    background-color: var(--el-color-primary-light-9); // Basic hover background
  }

  &.disabled {
    color: var(--el-text-color-disabled);
    cursor: not-allowed;
    background-color: transparent; // Ensure no hover effect on disabled
  }

  .menu-item-icon {
    width: 1em;
    height: 1em;
    margin-right: 8px;
    flex-shrink: 0; // Prevent icon shrinking
  }

  .menu-item-icon-placeholder {
    width: 1em;
    height: 1em;
    margin-right: 8px;
    flex-shrink: 0;
  }

  .menu-item-label {
    flex-grow: 1; // Allow label to take space
    margin-right: 10px; // Space before arrow/end
  }

  .submenu-arrow {
    margin-left: auto; // Push arrow to the right
    font-size: 0.8em;
    color: var(--el-text-color-secondary);
  }
}

// --- Drag and Drop Highlighting (Ensure DropTargetFolder component applies these classes) ---
.drop-target-folder { // Style for the drop target wrapper itself
  transition: background-color 0.2s ease, outline 0.2s ease; // Smooth transition
}

// The class name needs to match what DropTargetFolder.vue generates
:deep(.drop-target-folder.is-over) .item-content,
.filesystem-item-li:has(.drop-target-folder.is-over) {
  // Keep using Element Plus variables here for drop target indication, or create semantic ones if preferred
  background-color: var(--el-color-primary-light-9);
  outline: 2px dashed var(--el-color-primary);
  outline-offset: -2px;
}

// The class name needs to match what DropTargetFolder.vue generates
:deep(.drop-target-folder.cannot-drop) .item-content,
.filesystem-item-li:has(.drop-target-folder.cannot-drop) {
  cursor: not-allowed;

  & > * {
    opacity: 0.7;
  }
}

// Target the body of the el-card component
:deep(.el-card__body) {
  min-height: 300px; // Adjust this value as needed (e.g., 400px, 50vh)
  display: flex; // Use flex to help center empty state
  flex-direction: column; // Stack list/empty state vertically
}

// Ensure the list container and empty state can grow
.simple-list-container,
:deep(.el-empty) { // Target el-empty component using :deep
  flex-grow: 1; // Allow them to take up space
}

// Center the empty state content if needed
:deep(.el-empty) {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100%; // Make empty state fill the min-height area
}

.name-input {
  flex-grow: 1;
  align-self: center; // Explicitly align flex item vertically
  min-width: 150px;
  max-width: 450px; // Limit maximum width of the input box
  :deep(.el-input__inner) {
    font-size: 16px !important;
    line-height: normal;
    letter-spacing: inherit;
    font-family: inherit;
    // Apply the pulsing box-shadow animation
  }
}

// --- Global Rename Spotlight Overlay Style ---
.global-rename-spotlight-overlay {
  // Initialize radius variable
  position: fixed; // Cover the whole viewport
  // Slightly larger than viewport with negative offset to prevent edge clipping during scale animation
  top: -10vh;
  left: -10vw;
  width: 120vw;
  height: 120vh;
  // Use radial gradient for background to create spotlight effect
  // var(--spotlight-radius, 80px) defines the spotlight size (can be adjusted)
  // var(--spotlight-x, 50%) and var(--spotlight-y, 50%) define center, defaults to screen center
  // The gradient goes from transparent (hole) to the dark overlay color
  background: radial-gradient(
    /* Use the TARGET radius directly now */
          circle var(--target-spotlight-radius, 80px) at var(--spotlight-x, 50%) var(--spotlight-y, 50%),
          transparent 0%,
          transparent 100%, /* Sharp edge for the hole */
          rgba(0, 0, 0, 0.95) 100.1% /* Start darkening (almost opaque) just outside the hole */
  );

  pointer-events: none; // Allow interaction with elements underneath
  z-index: 1000; // Ensure it's above most content

  transform-origin: var(--spotlight-x, 50%) var(--spotlight-y, 50%); /* Scale from the spotlight center */
}

// --- Vue Transition Classes for Spotlight ---
.spotlight-enter-active {
  animation: spotlight-appear-bounce 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}

.spotlight-leave-active {
  animation: spotlight-disappear-expand-fade 0.3s ease-out forwards;
  /* Ensure transform origin is set during leave animation too */
  transform-origin: var(--spotlight-x, 50%) var(--spotlight-y, 50%);
}

// Style to hide the measurement canvas
.text-measure-canvas {
  position: absolute;
  left: -9999px;
  top: -9999px;
  visibility: hidden;
}

// --- Breadcrumb Drag-to-Open Style ---
// Target the new wrapper div for hover effect
.breadcrumb-wrapper {
  display: inline-block; // Make the div behave like the breadcrumb item
  margin: 0 5px; // Adjust margin as needed, similar to breadcrumb separator spacing
  border-radius: 4px; // Add some rounding
  transition: background-color 0.2s ease, outline 0.2s ease;

  // Make the inner item look normal by default
  :deep(.el-breadcrumb__item) {
    transition: none; // Remove transition from the item itself if set before
  }
  :deep(.el-breadcrumb__inner) {
    padding: 2px 6px; // Keep padding for better hover area
    border-radius: 3px;
    transition: background-color 0.2s ease, color 0.2s ease;
  }

  // Apply hover style directly to the wrapper
  &.breadcrumb-drop-target-hover {
    background-color: var(--el-color-primary-light-8);
    outline: 1px dashed var(--el-color-primary);
    outline-offset: 1px;
    cursor: alias;

    // Change text color inside when wrapper is hovered
    :deep(.el-breadcrumb__inner) {
      color: var(--el-color-primary-dark-2);
      background-color: transparent; // Ensure inner background doesn't conflict
    }
  }
}

// --- Force Draggable/Droppable wrappers to take full width ---
/* Target the DraggableItem component's rendered element */
/* We might need :deep() if DraggableItem styles are scoped */
:deep(.draggable-item) { /* Or just .draggable-item if styles are global */
  width: 100%;
  /* Ensure it behaves correctly as a direct child of flex li */
  /* display: block; might also be helpful if it's inline-block */
}

/* Ensure DropTargetFolder also allows its child to stretch */
/* We might need :deep() here too */
:deep(.drop-target-folder) { /* Or just .drop-target-folder */
  width: 100%; /* Ensure the wrapper also takes full width */
  display: block; /* Or grid/flex, ensure it's not inline */
}
// --- End Force Full Width ---

// --- Styles for Simulated List Header ---
.list-header {
  display: grid;
  // Change first gap column to 5px
  grid-template-columns: 24px 5px 1fr 45px 80px 45px 70px 45px 120px;
  /* column-gap: 20px; */ /* Remove column-gap */
  padding: 5px 12px;
  border-bottom: 1px solid var(--el-border-color-light);
  margin-bottom: 5px;
  font-size: 0.9em;
  color: var(--el-text-color-secondary);
  user-select: none;
  width: 100%; /* Ensure header takes full width */
  box-sizing: border-box; /* Ensure padding/border are included in width */
}

.header-item {
  cursor: pointer; /* Indicate clickable */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 2px 0; /* Add slight vertical padding */

  &:hover {
    color: var(--el-text-color-primary);
  }
}

// Align header text to match column content alignment
.header-name {
  grid-column: 3; /* Align with item-name */
  text-align: left;
}

.header-type {
  grid-column: 5; /* Align with item-type */
  text-align: left;
  /* margin-left: 35px; */ /* Removed */
}

.header-size {
  grid-column: 7; /* Align with item-size */
  text-align: right;
  /* margin-left: 35px; */ /* Removed */
}

.header-date {
  grid-column: 9; /* Align with item-modified */
  text-align: right;
  /* margin-left: 35px; */ /* Removed */
}
// --- End Header Styles ---

// --- Sorting Indicator Styles ---
.header-item {
  position: relative; // Needed for absolute positioning of pseudo-element

  &.is-active {
    font-weight: 600; // Bold text for active sort column
    color: var(--el-text-color-primary);
  }

  // Sorting direction indicator (arrow)
  &.is-active::after {
    content: '';
    border: 4px solid transparent;
    margin-left: 5px;
    display: inline-block;
    vertical-align: middle;
  }

  &.is-active.is-asc::after {
    border-bottom-color: var(--el-text-color-secondary); /* Arrow pointing up */
  }

  &.is-active.is-desc::after {
    border-top-color: var(--el-text-color-secondary); /* Arrow pointing down */
  }
}
// --- End Sorting Indicator Styles ---

</style>